import json
import time
import threading
from typing import Dict, Optional, Any

from mpmath.libmp.backend import python3
from nacos import NacosClient
from utils.logger import Logger
from utils.exceptions import NacosError
from utils.constants import (
    NACOS_SERVER_ADDRESSES, NACOS_NAMESPACE, NACOS_USERNAME,
    NACOS_PASSWORD, NACOS_CONFIG_GROUP, NACOS_CONFIG_DATA_ID,
    NACOS_CONFIG_REFRESH_INTERVAL
)

# 初始化日志
logger = Logger.get_logger(agent_name="nacos_config_client")

class NacosConfigClient:
    """Nacos配置客户端：拉取配置、动态刷新、降级兜底"""
    def __init__(self):
        # 初始化Nacos连接
        self.nacos_client = self._init_nacos_client()
        # 配置缓存（内存中存储最新配置）
        self.config_cache: Dict[str, Any] = {}
        # 本地降级配置路径
        self.fallback_config_path = "config/config_fallback.json"
        # 应急配置路径
        self.emergency_config_path = "config/emergency_config.json"
        # 动态刷新相关
        self.refresh_interval = NACOS_CONFIG_REFRESH_INTERVAL  # 刷新间隔（秒）
        self.refresh_thread = threading.Thread(target=self._auto_refresh_config, daemon=True)
        self.running = False
        # 加载初始配置（Nacos优先，失败则降级）
        self._load_initial_config()
        logger.info("NacosConfigClient初始化完成")

    def _init_nacos_client(self) -> NacosClient:
        """初始化Nacos客户端（复用constants配置）"""
        try:
            server_addrs = NACOS_SERVER_ADDRESSES.split(",")
            nacos_client = NacosClient(
                server_addrs=server_addrs,
                namespace=NACOS_NAMESPACE,
                username=NACOS_USERNAME,
                password=NACOS_PASSWORD
            )
            # 测试连接
            nacos_client.list_namespaces()
            logger.info(f"Nacos客户端连接成功: {server_addrs}")
            return nacos_client
        except Exception as e:
            logger.error(f"Nacos客户端初始化失败: {str(e)}", exc_info=True)
            raise NacosError(
                message="Nacos连接失败",
                context={"server_addresses": NACOS_SERVER_ADDRESSES}
            ) from e

    def _load_fallback_config(self) -> Dict[str, Any]:
        """加载本地降级配置（config_fallback.json）"""
        try:
            with open(self.fallback_config_path, "r", encoding="utf-8") as f:
                fallback_config = json.load(f)
            logger.warning(f"Nacos配置拉取失败，加载本地降级配置: {self.fallback_config_path}")
            return fallback_config
        except Exception as e:
            logger.error(f"本地降级配置加载失败: {str(e)}", exc_info=True)
            raise NacosError(
                message="Nacos和本地降级配置均加载失败",
                context={"fallback_path": self.fallback_config_path}
            ) from e

    def _load_initial_config(self) -> None:
        """加载初始配置（Nacos → 降级配置）"""
        try:
            # 从Nacos拉取配置
            config_str = self.nacos_client.get_config(
                data_id=NACOS_CONFIG_DATA_ID,
                group=NACOS_CONFIG_GROUP
            )
            if config_str:
                self.config_cache = json.loads(config_str)
                logger.info(f"从Nacos拉取配置成功: data_id={NACOS_CONFIG_DATA_ID}")
            else:
                # Nacos无配置，加载降级配置
                self.config_cache = self._load_fallback_config()
        except NacosError:
            # Nacos连接失败，直接加载降级配置
            self.config_cache = self._load_fallback_config()

    def _auto_refresh_config(self) -> None:
        """自动刷新配置（后台线程）"""
        while self.running:
            try:
                time.sleep(self.refresh_interval)
                # 拉取最新配置
                new_config_str = self.nacos_client.get_config(
                    data_id=NACOS_CONFIG_DATA_ID,
                    group=NACOS_CONFIG_GROUP
                )
                if new_config_str and new_config_str != json.dumps(self.config_cache):
                    new_config = json.loads(new_config_str)
                    self.config_cache = new_config
                    logger.info(f"Nacos配置动态刷新成功: data_id={NACOS_CONFIG_DATA_ID}")
                    # 触发配置变更通知（供其他模块监听）
                    self._notify_config_change()
            except Exception as e:
                logger.warning(f"Nacos配置刷新失败，沿用旧配置: {str(e)}")

    def _notify_config_change(self) -> None:
        """配置变更通知（可扩展：触发Agent重启、中间件重连等）"""
        # 此处可对接auxiliary_agents/config_sync.py的配置同步逻辑
        logger.debug("触发配置变更通知，各模块将自动应用新配置")

    def start_auto_refresh(self) -> None:
        """启动配置自动刷新"""
        if not self.running:
            self.running = True
            self.refresh_thread.start()
            logger.info(f"配置自动刷新启动，间隔: {self.refresh_interval}秒")

    def stop_auto_refresh(self) -> None:
        """停止配置自动刷新"""
        self.running = False
        self.refresh_thread.join(timeout=5)
        logger.info("配置自动刷新停止")

    def get_config(self, key: str, default: Any = None) -> Any:
        """获取配置项（支持嵌套key，如"agent.text_qa.max_concurrent"）"""
        keys = key.split(".")
        value = self.config_cache
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            logger.warning(f"配置项不存在: {key}，使用默认值: {default}")
            return default

    def get_full_config(self) -> Dict[str, Any]:
        """获取完整配置"""
        return self.config_cache.copy()

    def load_emergency_config(self) -> Dict[str, Any]:
        """加载应急配置（紧急场景启用，如限流、关闭非核心功能）"""
        try:
            with open(self.emergency_config_path, "r", encoding="utf-8") as f:
                emergency_config = json.load(f)
            # 应急配置覆盖现有配置
            self.config_cache.update(emergency_config)
            logger.warning(f"启用应急配置: {self.emergency_config_path}")
            return self.config_cache
        except Exception as e:
            logger.error(f"应急配置加载失败: {str(e)}", exc_info=True)
            raise NacosError(
                message="应急配置加载失败",
                context={"emergency_path": self.emergency_config_path}
            ) from e

# 单例实例（全局复用）
nacos_config_client = NacosConfigClient()